import {
  createCanvas,
  isArray,
  getStance,
  getCircleIntersection,
  getIntersectionAngle,
  getTwoPointMiddle,
} from "@/src/utils"
interface Position{
  x:number,
  y:number,
  [key:string]:any
}
interface TowerCraneParams{
  id:string,
  radius: number,
  angle?: number,
  position: Position,
  controlRoom?: number
};
class TowerCrane{
  public id:string;
  public radius:number;
  public angle:number;
  public position:Position;
  public controlRoom:number;
  constructor(params:TowerCraneParams){
    this.id = params.id;
    this.radius = params.radius;
    this.position = params.position;
    this.angle = params.angle||0;
    this.controlRoom = params.controlRoom||0;
  }
  updata(params:TowerCraneParams){
    this.radius = params.radius;
    this.position = params.position;
    this.angle = params.angle||0;
    this.controlRoom = params.controlRoom||0;
  }
  getRadiusPoint(_radius?:number):{x:number,y:number}{
    let {angle,position} = this;
    let radius = _radius||this.radius;
    let cosL = radius*Math.cos(angle*Math.PI/180),
        sinL = radius*Math.sin(angle*Math.PI/180);
    return {
      x: position.x + cosL,
      y: position.y + sinL
    }
  }
  private drawName(ctx){
    let {id,position} = this;
    ctx.textAlign="center";
    ctx.fillText(id,position.x,position.y);
  }
  private  drawDashRound (ctx,x, y, radius, _step = 5){
    const step = _step / 180 * Math.PI * 2;
    ctx.save();
    ctx.lineWidth=1;
    ctx.strokeStyle="#c3c3c3";
    ctx.lineCap="round";
    for (let b = 0, e = step / 2; e <= 360; b += step, e += step) {
      ctx.beginPath();
      ctx.arc(x, y, radius, b, e);
      ctx.stroke();
    }
    ctx.restore();
  }
  private drawControlRoom(ctx){
    let pointPos = this.getRadiusPoint(this.controlRoom);
    ctx.save();
    ctx.beginPath();
    ctx.fillStyle="blue";  
    ctx.arc(pointPos.x, pointPos.y, 3, 0, 2*Math.PI);
    ctx.fill();
    ctx.restore();
  }
  private drawArm(ctx){
    let {radius,position} = this;
    let pointPos = this.getRadiusPoint();
    ctx.beginPath();
    ctx.save();
    ctx.lineCap="round";
    ctx.lineWidth=1;
    ctx.strokeStyle="#6af04e";
    ctx.moveTo(position.x,position.y)
    ctx.lineTo(pointPos.x,pointPos.y);
    ctx.stroke();
    ctx.restore();
  }
  draw(ctx){
    let {radius,position} = this;
    this.drawName(ctx);
    this.drawDashRound(ctx,position.x,position.y,radius);
    this.drawArm(ctx);
    this.drawControlRoom(ctx);
  }
}

class BuildingSite{
  private height:number;
  private width:number;
  private canvas:HTMLCanvasElement;
  private ctx;
  public scale:number;
  private towerCranes:Array<TowerCrane>;
  constructor({scale=1,contenter}:{scale?:number,contenter:HTMLElement}){
    this.scale = scale;
    this.towerCranes = [];
    this.canvas = createCanvas(contenter);
    this.ctx = (this.canvas as any).ctx;
    this.width = contenter.clientWidth;
    this.height = contenter.clientHeight;
    this.ctx.translate(0.5,0.5);
  }
  private addTowerCrane(towerCrane:TowerCrane){
    this.towerCranes.push(towerCrane);
  }
  deleteTowerCrane(params:string|Array<string>){
    let list:Array<string> = [];
    if(!isArray(params)){
      list.push(params as string);
    }else{
      list = params as Array<string>;
    }
    this.towerCranes = this.towerCranes.filter(item=>{
      return list.indexOf(item.id) == -1;
    })
    this.draw();
  }
  private clean(){
    this.ctx.clearRect(0,0,this.canvas.height,this.canvas.width);
  }
  updata(params:TowerCraneParams|Array<TowerCraneParams>){
    let scale = this.scale;
    let list:Array<TowerCraneParams> = [];
    if(!isArray(params)){
      list.push(params as TowerCraneParams);
    }else{
      list = params as Array<TowerCraneParams>;
    }
    list.forEach((_lt,index)=>{
      let lt:TowerCraneParams = JSON.parse(JSON.stringify(_lt));
      let nowItem = this.towerCranes.find(item=>item.id==lt.id);
      lt.radius = ~~lt.radius*scale;
      lt.position.x = ~~lt.position.x*scale;
      lt.position.y = ~~lt.position.y*scale;

      if(nowItem){
        nowItem.updata(lt);
      }else{
        this.addTowerCrane(new TowerCrane(lt));
      }
    })
    this.draw();
  }
  private isIn(towerCrane:TowerCrane):boolean{
    let {height,width} = this;
    let {position,radius} = towerCrane;
    if(position.x + radius < 0){
      return false;
    }
    if(position.x - radius > width){
      return false;
    }
    if(position.y + radius < 0){
      return false;
    }
    if(position.y - radius > height){
      return false;
    }
    return true;
  }
  private drawOverlap(){
    let {ctx,towerCranes} = this;
    let length = towerCranes.length;
    for(let i = 0; i < length; i++){
      let startPoint = towerCranes[i];
      let {position:pos1,radius:r1} = startPoint;
      for(let k = i+1; k < length;k++){
        let endPoint = towerCranes[k];
        let {position:pos2,radius:r2} = endPoint;
        let stance = getStance(pos1,pos2);
        //判断是否相交(!!!包含圆暂时不做处理)
        if(stance < r1+r2 && stance + r1 > r2 && stance + r2 > r1){ 
          //两个圆交点  
          let circleIntersections = getCircleIntersection({...pos1,radius:r1},{...pos2,radius:r2});
          //圆上的点与x正轴夹角
          let startAngle1 = getIntersectionAngle(pos1,circleIntersections[0]),
              endAngle1 = getIntersectionAngle(pos1,circleIntersections[1]),
              startAngle2 = getIntersectionAngle(pos2,circleIntersections[0]),
              endAngle2 = getIntersectionAngle(pos2,circleIntersections[1]);
          //割线中点坐标，肯定在圆心的连线上
          let circleIntersectionsCenter = {
            x: (circleIntersections[0].x+circleIntersections[1].x)/2,
            y: (circleIntersections[0].y+circleIntersections[1].y)/2,
          };
          //顺时针还是逆时针画
          let counterclockwise1 = false,
              counterclockwise2 = false;
          //开始角度要比结束角度小
          if(startAngle1 - endAngle1 > 0){
            let middleValue = startAngle1;
            startAngle1 = endAngle1;
            endAngle1 = middleValue;
          }
          if(startAngle2 - endAngle2 > 0){
            let middleValue = startAngle2;
            startAngle2 = endAngle2;
            endAngle2 = middleValue;
          } 
          //判断逆时针还是顺时针
          if(pos1.x < pos2.x){ //startPoint在左侧 endPoint在右侧
            if(circleIntersectionsCenter.x < pos1.x){//startPoint取大角
              if(endAngle1 - startAngle1 < Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 > Math.PI){
                counterclockwise2 = true;
              }
            }else if(circleIntersectionsCenter.x > pos2.x){//endPoint取大角
              if(endAngle1 - startAngle1 > Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 < Math.PI){
                counterclockwise2 = true;
              }
            }else{//都取小角
              if(endAngle1 - startAngle1 > Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 > Math.PI){
                counterclockwise2 = true;
              }
            }
          }else if(pos1.x > pos2.x){ //startPoint在右侧 endPoint在左侧
            if(circleIntersectionsCenter.x > pos1.x){//startPoint取大角
              if(endAngle1 - startAngle1 < Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 > Math.PI){
                counterclockwise2 = true;
              }
            }else if(circleIntersectionsCenter.x < pos2.x){//endPoint取大角
              if(endAngle1 - startAngle1 > Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 < Math.PI){
                counterclockwise2 = true;
              }
            }else{//都取小角
              if(endAngle1 - startAngle1 > Math.PI){
                counterclockwise1 = true;
              }
              if(endAngle2 - startAngle2 > Math.PI){
                counterclockwise2 = true;
              }
            }
          }else{
            if(pos1.y < pos2.y){//startPoint在上侧 endPoint在下侧
              if(circleIntersectionsCenter.y < pos1.y){//startPoint取大角
                if(endAngle1 - startAngle1 < Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 > Math.PI){
                  counterclockwise2 = true;
                }
              }else if(circleIntersectionsCenter.y > pos2.y){//endPoint取大角
                if(endAngle1 - startAngle1 > Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 < Math.PI){
                  counterclockwise2 = true;
                }
              }else{//都取小角
                if(endAngle1 - startAngle1 > Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 > Math.PI){
                  counterclockwise2 = true;
                }
              }
            }else if(pos1.y > pos2.y){//startPoint在下侧 endPoint在上侧
              if(circleIntersectionsCenter.y > pos1.y){//startPoint取大角
                if(endAngle1 - startAngle1 < Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 > Math.PI){
                  counterclockwise2 = true;
                }
              }else if(circleIntersectionsCenter.y < pos2.y){//endPoint取大角
                if(endAngle1 - startAngle1 > Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 < Math.PI){
                  counterclockwise2 = true;
                }
              }else{//都取小角
                if(endAngle1 - startAngle1 > Math.PI){
                  counterclockwise1 = true;
                }
                if(endAngle2 - startAngle2 > Math.PI){
                  counterclockwise2 = true;
                }
              }
            }
          }
          ctx.save();
          ctx.beginPath();
          ctx.fillStyle="rgba(255,0,0,1)";
          if(counterclockwise1){
            ctx.arc(pos1.x,pos1.y,r1,startAngle1+0.02,endAngle1+0.02,counterclockwise1);
          }else{
            ctx.arc(pos1.x,pos1.y,r1,startAngle1-0.02,endAngle1+0.02,counterclockwise1);
          }
          ctx.fill();
          ctx.closePath();  
          ctx.beginPath();
          if(counterclockwise2){
            ctx.arc(pos2.x,pos2.y,r2,startAngle2+0.02,endAngle2+0.02,counterclockwise2);
          }else{
            ctx.arc(pos2.x,pos2.y,r2,startAngle2-0.02,endAngle2+0.02,counterclockwise2);
          } 
          ctx.fill();
          ctx.closePath();   
          ctx.restore();
        }  
      }     
    } 
  }
  private connectTowerCrane(){
    let {ctx,height,width} = this;
    let {towerCranes} = this;
    let length = towerCranes.length;
    ctx.save();
    ctx.lineCap="round";
    ctx.lineWidth=1;
    ctx.strokeStyle="#c3c3c3";
    for(let i = 0; i < length; i++){
      let startPoint = towerCranes[i].getRadiusPoint();
      for(let k = i+1; k < length;k++){
        let endPoint = towerCranes[k].getRadiusPoint();
        let middlePoint = getTwoPointMiddle(startPoint,endPoint);
        ctx.beginPath();
        ctx.moveTo(startPoint.x,startPoint.y);
        ctx.lineTo(endPoint.x,endPoint.y);
        ctx.textAlign="center";
        ctx.fillText(middlePoint.length,middlePoint.x,middlePoint.y);
        ctx.stroke();
      }
    }
    ctx.restore();
  }
  draw(){
    let {ctx,height,width} = this;
    this.clean();
    this.drawOverlap();
    this.towerCranes.forEach(tc=>{
      if(this.isIn(tc)){
        tc.draw(ctx);
      }
    });
    this.connectTowerCrane();
  }
}

export default function({scale=1,contenter}:{scale?:number,contenter:HTMLElement}){
  return new BuildingSite({scale,contenter});
}